﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using System.Xml.Serialization;
using System.Diagnostics;

using SharedGenomics.Core;
using SharedGenomics.Annotations;
using SharedGenomics.Workbench.Core;
using SharedGenomics.Workbench.Messages;

namespace SharedGenomics.Workbench.Services
{
    /// <summary>
    /// An IAnnotationNotifier that records the annotations that have been viewed.
    /// </summary>
    public class RecordingAnnotationNotifier : IAnnotationNotifier, IEventSubscriber<AnnotationResultsLoadedMessage>, IEventSubscriber<AnnotationDisplayMessage>
    {
        private Guid annotationSessionId;
        private int? loadedResultsJobId;
        private readonly IAnnotationSessionService annotationSessionService;

        public RecordingAnnotationNotifier(IAnnotationSessionManager sessionManager, IAnnotationImageUploader imageUploader, IAnnotationSessionService annotationService)
        {
            this.SessionManager = sessionManager;
            this.ImageUploader = imageUploader;
            this.annotationSessionService = annotationService;

            this.annotationSessionId = Guid.Empty;
        }

        public void CaptureAnnotation(Guid id, IAnnotation annotation, Image annotationImage)
        {
            annotation.ThrowIfNull("annotation");
            annotationImage.ThrowIfNull("annotationImage");

            string description = annotation.Description;
            string encodedKey = annotation.EncodedKey;

            Debug.Assert(this.loadedResultsJobId.HasValue);
            int jobId = this.loadedResultsJobId.Value;

            // Ensure there's an annotation session
            if (Guid.Empty.Equals(this.annotationSessionId))
            {
                // First annotation - magic a session out of thin air and save it.  TODO: Only do this for auto-annotations
                this.annotationSessionId = this.SessionManager.CreateSession(jobId);
            }

            //create the annotation record on the server
            this.annotationSessionService.AddViewedAnnotation(id, this.annotationSessionId, null, TimeService.Now(), false, encodedKey, description);

            //upload the image
            this.ImageUploader.UploadAnnotationImage(id, annotationImage);
        }

        public void SetAnnotationImportance(Guid id, bool isImportant)
        {
            this.SessionManager.SetViewedAnnotationImportance(id, isImportant);
        }

        public void Receive(AnnotationResultsLoadedMessage message)
        {
            this.loadedResultsJobId = message.JobId;
        }

        public void Receive(AnnotationDisplayMessage message)
        {
            message.ThrowIfNull("message");
            this.CaptureAnnotation(message.Identifier, message.Annotation, message.Image);
        }

        private string GetEncodedKey(IAnnotation annotation)
        {
            XmlSerializer serializer = new XmlSerializer(annotation.GetType());
            StringBuilder sb = new StringBuilder();
            using (TextWriter textWriter = new StringWriter(sb))
            {
                serializer.Serialize(textWriter, annotation);
            }
            return sb.ToString();
        }

        private IAnnotationImageUploader ImageUploader { get; set; }
        private IAnnotationSessionManager SessionManager { get; set; }
    }
}
